// Structures
struct sPointLight
{
    float4 Color;
    float4 Position;
    float FallOff;
    float Range;
};

struct sMaterial
{
	float4 DiffuseColor;
	float SpecularPower;
	float SpecularIntensity;
	float4 SpecularColor;
};


struct VertexShaderInput
{
    float4 Position : POSITION0;
	float3 Normal : NORMAL0;
};

struct VertexShaderOutput
{
	float4 Position : POSITION0;
	float3 WorldNormal : TEXCOORD1;
	float3 WorldPosition : TEXCOORD2;
};


// Space / View Parameters
float4x4 World;
float4x4 View;
float4x4 Projection;
float3 CameraPosition;


// Lighting Parameters
float4 AmbientLight;
int NumPointLights = 3;
sPointLight PointLights[8];

// Material Parameters
sMaterial Material;


// Functions
float4 CalcPointLight(sPointLight pointLight, 
					float3 worldPosition, 
					float3 worldNormal, 
					sMaterial material
					)
{
     float3 lightVector = pointLight.Position - worldPosition;
     float lightDist = length(lightVector);
     float3 directionToLight = normalize(lightVector);
     
     //calculate the intensity of the light with exponential falloff
     float baseIntensity = pow(saturate((pointLight.Range - lightDist) / pointLight.Range),
                                 pointLight.FallOff);
     
     
     float diffuseIntensity = saturate( dot(directionToLight, worldNormal));
     float4 diffuse = diffuseIntensity * pointLight.Color * material.DiffuseColor;

     //calculate Phong components per-pixel
     float3 reflectionVector = normalize(reflect(-directionToLight, worldNormal));
     float3 directionToCamera = normalize(CameraPosition - worldPosition);
     
     //calculate specular component
     float4 specular = saturate(pointLight.Color * material.SpecularColor * 
						material.SpecularIntensity * 
						pow(saturate(dot(reflectionVector, directionToCamera)), 
                           material.SpecularPower));
                           
     return  baseIntensity * (diffuse + specular);
}


// Vertex Shader
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);

    output.WorldNormal =  mul(input.Normal, World);
    output.WorldPosition = worldPosition / worldPosition.w;
	
    return output;
}


// Pixel Shader
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    float4 diffuseColor = Material.DiffuseColor;
    float4 specularColor = Material.DiffuseColor;
    
    float4 color = AmbientLight * diffuseColor;
    
    for (int i = 0; i < NumPointLights; i++)
    {
        color += CalcPointLight(
					PointLights[i], 
					input.WorldPosition, 
					input.WorldNormal,
					Material);
    }
    color.a = 1.0;
    return color;
}


// Techniques
technique Technique1
{
    pass Pass1
    {
        //set sampler states
        
        
        
        // set render states
        AlphaBlendEnable = FALSE;

        //set pixel shader states
        VertexShader = compile vs_3_0 VertexShaderFunction();
        PixelShader = compile ps_3_0 PixelShaderFunction();
    }
}

